package org.shj.basic

import scala.reflect.ClassTag

class Person1(val name: String){
  def talk(person : Person1) { 
    println(this.name + " talk to " + person.name)
  }
}

class Worker(name: String) extends Person1(name)

class Dog1(val name: String)


// <: 限定了 泛型 T 必须是 Person1或其子类
class Club[T <: Person1](p1 : T, p2: T){
  def communicate = p1.talk(p2)
}

// <% 表示 泛型T 可以不是Person1类或其子类，但是必须隐式转换成Person1类型
class Breed[T <% Person1](p1 : T, p2: T){
  def breedDog = p1.talk(p2)
}

// T: ClassTag 表示在编译的时候类型信息不够，需要借助JVM的Runtime来通过运行时信息获得完整的
//类型信息
class Test[T: ClassTag]{
  
}

class Engineer
class Expert extends Engineer

//  -T 表示逆变, 如果方法中的参数指定为 Meeting[Expert], 则此方法也接受 Meeting[Engineer]
// 因为Engineer是Expert的父类，因为逆变的原因，
class Meeting[-T]

// +T 表示协变。 与逆变相反
class Meeting2[+T]

// T:Ordering 这种语法必须能够变成 Ordering[T]
class Maximum[T: Ordering](val x: T, val y:T){
  def bigger(implicit ord : Ordering[T]) = {
    if(ord.compare(x, y) > 0) x else y
  }
}
  
object TypeDemo {
  def main(args: Array[String]): Unit = {
    implicit def dog2Person(dog : Dog1) = new Person1(dog.name)
    
    val p1 = new Person1("Jack")
    val p2 = new Worker("Rose")
    val c = new Club(p1,p2)
    c.communicate
    
    println("========= [T <% Person1] demo =========")
    val dog = new Dog1("dahuang")
    val b = new Breed[Person1](p1, dog)
    b.breedDog
    
    println("======= 逆变 [-T]  demo ======")
    val eng = new Meeting[Engineer]
    val ext = new Meeting[Expert]
    participateMeeting(eng)
    participateMeeting(ext)
    
    println("======= 协变 [+T]  demo ======")
    val eng2 = new Meeting2[Engineer]
    val ext2 = new Meeting2[Expert]
    participateMeeting2(eng2)
    participateMeeting2(ext2)
    
    println("======= [T: Ordering]  demo ======")
    println(new Maximum(2,5).bigger)
    println(new Maximum("Scala", "Java").bigger)
  }
  
  def participateMeeting(meeting: Meeting[Expert]){
    println("welcome")
  }
  
  def participateMeeting2(meeting: Meeting2[Engineer]){
    println("welcome2")
  }
}